import type { DirectiveBinding, VNode, App, Directive } from 'vue'

export interface IDirective {
  // 在绑定元素的 attribute 前
  // 或事件监听器应用前调用
  created?(el?: Element, binding?: DirectiveBinding, vnode?: VNode, prevVnode?: VNode): void
  // 在元素被插入到 DOM 前调用
  beforeMount?(el?: Element, binding?: DirectiveBinding, vnode?: VNode, prevVnode?: VNode): void
  // 在绑定元素的父组件
  // 及他自己的所有子节点都挂载完成后调用
  mounted?(el?: Element, binding?: DirectiveBinding, vnode?: VNode, prevVnode?: VNode): void
  // 绑定元素的父组件更新前调用
  beforeUpdate?(el?: Element, binding?: DirectiveBinding, vnode?: VNode, prevVnode?: VNode): void
  // 在绑定元素的父组件
  // 及他自己的所有子节点都更新后调用
  updated?(el?: Element, binding?: DirectiveBinding, vnode?: VNode, prevVnode?: VNode): void
  // 绑定元素的父组件卸载前调用
  beforeUnmount?(el?: Element, binding?: DirectiveBinding, vnode?: VNode, prevVnode?: VNode): void
  // 绑定元素的父组件卸载后调用
  unmounted?(el?: Element, binding?: DirectiveBinding, vnode?: VNode, prevVnode?: VNode): void
}

export interface ICustomDirectiveElement extends Element {
  [key: string]: any
}

interface IDirectives {
  [key: string]: IDirective
}

const directives: IDirectives = {}
const setUpDirectives = (app: App<Element>) => {
  Object.keys(directives).forEach((key) => {
    if (Object.hasOwnProperty.call(directives, key) && directives[key]) {
      app.directive(key, directives[key] as Directive<Element | undefined, any>)
    }
  })
}

export default setUpDirectives
